Skip to content

Add measurement-validator module: Pretext vs DOM divergence detection#1

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/add-measurement-validator
Draft

Add measurement-validator module: Pretext vs DOM divergence detection#1
Copilot wants to merge 2 commits intomainfrom
copilot/add-measurement-validator

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 4, 2026

Pretext users have no standard way to verify that canvas-based measurements match actual browser DOM rendering — silent divergences (font fallback, bidi shaping, emoji inflation, etc.) propagate silently into layout.

Adds src/measurement-validator.ts exported as ./measurement-validator, with four components:

  • MeasurementComparator — compares layoutWithLines() output against live DOM geometry; pretextOnly: true mode stubs DOM reads for Node/test environments
  • DivergenceClassifier — infers root cause from text content and per-line delta data: bidi, emoji, pre-wrap, variable-font, font-fallback, unknown
  • TestSuiteRunner — runs a MeasurementSample[] corpus, aggregates into SuiteReport; failOn threshold + runOrThrow() for CI gating
  • ReportGenerator — renders SuiteReport as text | json | html
import { MeasurementComparator, TestSuiteRunner, ReportGenerator } from '@chenglou/pretext/measurement-validator'

// Single comparison (browser)
const result = new MeasurementComparator().compare({
  text: 'Hello world', font: '16px Inter', maxWidth: 300, lineHeight: 20,
})
// result.severity, result.causes, result.lines[n].delta …

// Batch CI validation
const runner = new TestSuiteRunner({ failOn: 'error' })
const report = runner.runOrThrow(corpus)
console.log(new ReportGenerator().render(report, 'html'))

Severity buckets: exact (0 px) → minor (<0.5 px) → major (<2 px) → critical (≥2 px or line-count mismatch).

Original prompt

Measurement Validator PRD: Professional In-Depth Planning

CONTEXT & VALIDATION

This document is the result of 5+ hours of research across:


PROBLEM STATEMENT

Current State

Pretext is a high-performance text measurement library used by 9+ shipping products to avoid DOM layout reflow. However, there is no standard way to validate that Pretext's canvas-based measurements match actual browser DOM rendering.

Real-world impact:

  • liyown/marknative (Markdown → PNG/SVG) silently produces wrong output if fonts fail to load
  • xiaoiver/infinite-canvas (WebGL whiteboard) renders text at wrong positions if measurements diverge
  • fastrepl/char (code editor) can't guarantee layout accuracy
  • zuoban/zb-reader (EPUB reader) experiences layout shift on different fonts
  • All 9 apps are individually solving the same problem

Root Cause

Issue chenglou#77 reveals the core problem:

"canvas.measureText(text) with font A"
vs.
"DOM rendering with font A"
can diverge by 5-20px depending on:
  1. Font loading state (fallback vs. loaded)
  2. Browser-specific rendering (Chrome vs. Safari vs. Firefox)
  3. Bidi text shaping (RTL/LTR visual order)
  4. Emoji/emoji-presentation handling
  5. Font features (kerning, ligatures)

Current workaround: Hope the measurements are correct. Use DOM as fallback if broken.

Why This Matters

  • Measurement = foundation of layout. If wrong, everything downstream is wrong.
  • Silent failures are worse than loud ones. An app using wrong measurements doesn't know it's wrong until users complain.
  • Every Pretext user needs this. Not optional infrastructure; critical QA tool.

SCOPE & OBJECTIVES

PRIMARY GOAL

Build a Measurement Validator that:

  1. Detects divergence between Pretext's canvas measurements and browser DOM measurements
  2. Quantifies severity (minor <0.5px, major <2px, critical >2px)
  3. Identifies root cause (font fallback, bidi, emoji, kerning, etc.)
  4. Produces actionable reports (JSON, HTML, CI integration)
  5. Integrates with Pretext test suite (corpus validation)

SECONDARY GOALS

  1. Become official Pretext stdlib module (@pretext/measurement-validator)
  2. Unblock 9 shipping apps (they get a tool to validate before deployment)
  3. Feed back findings to Pretext core (improve accuracy, add workarounds)

OUT OF SCOPE

  • Fixing Pretext measurements (that's Pretext's job)
  • Custom canvas backends (measurement is canvas-specific)
  • Font rendering engine (we trust canvas.measureText as ground truth)

TECHNICAL ARCHITECTURE

Component 1: Measurement Comparator

Purpose: Compare Pretext vs. DOM for a single text sample

Input:

interface MeasurementSample {
  text: string
  font: string
  maxWidth?: number
  lineHeight?: number
  whiteSpace?: 'normal' | 'pre-wrap'
  locale?: string
  direction?: 'ltr' | 'rtl'
  platform?: 'chrome' | 'firefox' | 'safari' | 'node'
}

Output:

interface MeasurementResult {
  sample: MeasurementSample
  
  // Line measurements
  pretextLineCount: number
  domLineCount: number
  lineMismatch: boolean
  
  // Geometry
  pretextHeight: number
  domHeight: number
  heightDelta: number
  heightPercentError: number
  
  // Per-line breakdown
  lines: {
    index: number
    pretextWidth: number
    domWidth: number
    delta: number
    text: string
    severity: 'exact' | 'minor' | 'major' | 'critical'
  }[]
  
  // Metadata
  severity: 'pass' | 'warning' | 'error' | 'critical'
  timestamp: string
  platform: string
  viewport: { width: number; height: number }
}

Algorithm:

  1. Prepare text with Pretext
  2. Measure with Pretext's layout()
  3. Create DOM element with same font/whiteSpace
  4. Measure DOM (offsetHeight, offsetWidth per line)
  5. Compare line-by-line
  6. Classify divergence

Component 2: Test Suite Runner

Purpose: Run validator against corpus of test cases

Input:

  • Pretext's existing corpus (20+ languages, mixed scripts)
  • Font matrix (system fonts, web fonts, fallbacks)
  • Width matrix (narrow 300px → wide 1200px)

Output:

  • Pass/Fail per sample
  • Aggregated report (% passing, % warnings, critical cases)
  • Performance metrics (compare time to measure)

Test Coverage:

├─ LTR Languages (English, Spanish, French)
├─ RTL Languages (Arabic, Hebrew, Urdu)
├─ CJK Languages (Chinese, Japanese, Korean)
├─ Complex Scripts (Thai, Myanmar, Khmer, Devanagari)
├─ Mixed Bidi (English + Arabic in same line)
├─ Emoji + ZWJ sequences
├─ Font Fallback Scenarios
│   ├─ Font not loaded → system fallback
│   ├─ Font loaded → rendered font
│   └─ Font ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

…, and test suite

Agent-Logs-Url: https://github.com/Himaan1998Y/pretext/sessions/7bfad683-e3dc-4ab7-8671-45485362c873

Co-authored-by: Himaan1998Y <210527591+Himaan1998Y@users.noreply.github.com>
Copilot AI changed the title [WIP] Add measurement validator for Pretext canvas comparisons Add measurement-validator module: Pretext vs DOM divergence detection Apr 4, 2026
Copilot AI requested a review from Himaan1998Y April 4, 2026 18:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants